home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / The Hacks! / PCA Icon Arranger ƒ / TransSkel.p < prev   
Encoding:
Text File  |  1998-06-20  |  63.4 KB  |  2,067 lines  |  [TEXT/PJMM]

  1. {    TransSkel version 2.00 - Transportable application skeleton}
  2.  
  3. {    TransSkel is public domain and was originally written in LightSpeed C by:}
  4.  
  5. {            Paul DuBois}
  6. {            Wisconsin Regional Primate Research Center}
  7. {            1220 Capital Court}
  8. {            Madison WI  53706  USA}
  9.  
  10. {    UUCP:    [allegra,ihnp4,seismo]!uwvax!rhesus!dubois }
  11. {    ARPA:    dubois@rhesus.primate.wisc.edu}
  12. {    The Pascal Version of TransSkel is public domain and was ported and changed by        }
  13.  
  14. {            Owen Hartnett            }
  15. {            Ωhm Software            }
  16. {            163 Richard Drive        }
  17. {            Tiverton, RI 02878        }
  18.  
  19. {    CSNET:    omh@cs.brown.edu.CSNET                                             }
  20. {    ARPA:        omh%cs.brown.edu                                                    }
  21. {    UUCP:        [ihnp4,allegra]!brunix !omh                                            }
  22.  
  23. {    This version of TransSkel written for Lightspeed Pascal.  Lightspeed Pascal is a}
  24. {    trademark of:}
  25. {            THINK Technologies, Inc}
  26. {            420 Bedford Street  Suite 350}
  27. {            Lexington, MA  02173  USA}
  28.  
  29. {  History}
  30. {  06/13/86    Beta version. (pd) }
  31. {  08/27/86    Version number changed to 1.01.(pd)}
  32. {              v1.0 DoGrow bug fixed - the port at the point of the}
  33. {              InvalRect could have been anything; the fix is to set}
  34. {              the port to the grown window first.  This also explains}
  35. {              why the kludge to DoActivate in v1.0 worked.(pd)}
  36. {  10/02/86    Version number changed to 1.02, as a result of adding}
  37. {            modifications by David W. Berry (well!dwb@lll-lcc.arpa)}
  38. {            for supporting window zooming.  Also used his modifications}
  39. {            for supporting modeless dialogs (though not in the same}
  40. {            form).  Dialogs can be #define'd on or off.(pd)}
  41.  
  42. {12/ 28 / 86 Version number changed to 1.03 . Modified to work under LightspeedC v . 2.01 }
  43. {            - took out definitions for window zooming stuff , as it is now supported by the compiler}
  44. {             directly . Also declared DoZoom static , fixing an oversight . ( pd )}
  45. { 01 / 18 / 86 Put a SetPort into DoZoom - ZoomWindow requires port to be}
  46. {            set to window being zoomed . ( pd )}
  47. { 02 / 05 / 86 Version number changed to 1.04 . Big change : port setting behavior made explicit}
  48. {             - the only persistant switch occurs when a window comes active . This changes }
  49. {            underlying programming model ( see manual for detailed discussion ) . Thanks to}
  50. {             Duane Williams for pointing out that this should be done . Typedef 'd }
  51. {            integer/long variables to Integer, Longint to facilitate coversion to other C }
  52. {            compilers . More complete type-casting done . LightspeedC does a lot of it }
  53. {            automatically , other compilers may not . ( pd - this version never released ) }
  54. {03 / 02 / 87 Fixed bug whereby clicks in drag region of non - active windows may not bring }
  55. {            window to front . Seems to be due to DragWindow calling StillDown to see    if mouse is still }
  56. {            down .    If the machine was busy    otherwise when click occurred and }
  57. {            mouse already up when DragWindow is called , the click ends up being ignored . }
  58. {            Thanks to Roger Humphrey for finding this one . }
  59.  
  60. {* * * Changes implemented first by omh to Pascal Version}
  61.  
  62. { 12/24/86  Finished first Pascal version.   Dialogs cannot be defined off.     (omh)}
  63.  
  64. {4 / 18 / 87 Changed Desk Accessory code so it 's more tolerant of memory}
  65. {            conditions for desk accessories . ( omh ) }
  66. {7 / 12 / 87 Added "cache " code to GetWDHandler . Now TransSkel figures }
  67. {            that an event is most likely to occur for the same window as the previous }
  68. {            event . Thus the WindowPtr and WDHandle for events are cached and examined }
  69. {            to avoid searching through the handler list . ( omh ) }
  70. {7 / 12 / 87 Excised the notorious "SetPort "excess . As pointed out by Duane Williams ,}
  71. {             SetPort traps abounded unnecessarily in version 1.02 . These have been eliminated }
  72. {            now with two exceptions . First , the port is set when a window handler }
  73. {            is installed . The justification for this is that when a handler is installed , it }
  74. {            is likely that further processing will be done on it immediately . The application gets }
  75. {            control immediately after the handler is installed anyway , so this behavior can be manually }
  76. {            overridden where necessary . Second , when a window is activated , the port is}
  77. {            set to it . This follows the model of keeping the port in sync with the }
  78. {            active window . ( omh ) }
  79. {7 / 14 / 87 Added grow zone function installation    and MoreMasters to SkelInit , }
  80. {            which now requires two parameters . The first indicates the number of times to call }
  81. {            MoreMasters . The second is a ProcPtr indicating a user - supplied grow zone}
  82. {            function to be called when memory problems occur .  If nil , no grow zone}
  83. {            function is    installed . ( omh ) }
  84. {7 / 14 / 87 SkelMenu , SkelWindow , and SkelDialog now return zero or non - zero to indicate }
  85. {            failure or success of handler allocation . This could break * all * previous TransSkel }
  86. {            applications ( as will the change to SkelInit , above . Please see the section "How to }
  87. {            adapt old TransSkel to New "    in the manual    for detailed specifications on }
  88. {            how to convert your old programs . TransSkel becomes more memory conscious}
  89. {            with these changes . The functions SkelMenu , SkelWindow , and }
  90. {            SkelDialog are the only routines which actually allocate memory . Since they may be }
  91. {            called at any time , knowing that you have enough memory becomes important . Thus , }
  92. {            these routines return a value to indicate what happened .  If they return zero ,}
  93. {             then memory allocation failed . ( omh ) }
  94. {10 / 21 / 87 Added another parameter to SkelMenu:  drawBar: Boolean . This tells SkelMenu }
  95. {            whether to draw the menu bar after adding the Menu . This is done to eliminate }
  96. {            the menus popping up one at a time . Simply call SkelMenu  with drawBar false}
  97. {            until the    last time you call SkelMenu , then call it (for the last menu )}
  98. {            with drawBar true . ( omh ) }
  99. {10 / 26 / 87 Removed declarations for zoom - in and zoom - out . Added Pascal }
  100. {            changes ( above ) to C version . ( omh )}
  101.  
  102. {    02 / 02 / 88 Merged pd 's 1.04 changes with those of omh, above, to create}
  103. {            release version 2.0 . Fixed bug whereby cmd - key equivalents}
  104. {            for menu selections would execute twice if DA window in front . Thanks }
  105. {            to Don Fredkin and Julian Vrieslander for finding this one , and to Don for the}
  106. {             best fix . ( pd ) }
  107. { 10/28/88 Removed all New Rom calls. }
  108. { 10/28/88 Added support for conditional compilation for dialogs and MPW support.  By setting }
  109. {            the Think_pascal flag to false, TransSkel will run under MPW. Now correctly written for LSP 2.0}
  110.  
  111. {Some fixes done later by Ingemar Ragnemalm. Search for "Ingemar" fo find these.}
  112. {They include some bug fix and hierarcical menu support (call SkelHMenu instead of SkelMenu}
  113. {for those menus).}
  114.  
  115. {New fix 18/9-93: Added a filter proc for dialogs, to allow special event processing before}
  116. {an event is passed to IsDialogEvent, when a modeless dialog is in the front. This makes it possible}
  117. {to use user items in modeless dialogs, and to handle return/enter.}
  118.  
  119. {Added WNE-support. Use SkelSetSleep and SkelSetMouseRgn if you need them. /Ingemar}
  120.  
  121. {Added FindWindowByRefcon, a routine that is useful for certain multi-window appplications.}
  122.  
  123. {july -94: Plugged in suspend/resume-handlers, conforming with TransSkel 3.0. (Handler should}
  124. {take a boolean as parameter. If the boolean is true, the application was resumed, otherwise it was}
  125. {suspended.) Processes Apple Events by calling AEProcessAppleEvent for you.}
  126.  
  127. {Mouse moved events, added by Ingemar jan -95:}
  128.  
  129. {August 1997: Finally, full PPC support with no separate C glue!}
  130. {October 1997: Changed CallPMouse slightly for CWPro 1 compatibility}
  131. {November 1997: Bug fixed in GetDHandler}
  132. {February 1998: SkelReqdAEInit for core AE support, with callbacks}
  133. {March 1998: SkelGetAppleMenu to access a private global to modify the Apple menu }
  134.  
  135.  
  136. unit TransSkel;
  137.  
  138. interface
  139.  
  140. {$IFC UNDEFINED GENERATINGPOWERPC }
  141. {$SETC GENERATINGPOWERPC:= false }
  142. {$ENDC}
  143.  
  144. {$SETC supportDialogs:= true }
  145.                     { Set to false to disallow modeless dialog support and save code space }
  146.                 { Set to false to have SkelInit call QuickDraw Inits: InitGraf, InitDialog, etc. }
  147.  
  148. {$IFC UNDEFINED THINK_PASCAL}
  149.     uses
  150.         Types, Quickdraw,{, OSIntf, ToolIntf, PackIntf}
  151.         Dialogs, Menus, Windows, Memory, SegLoad, Scrap, ToolUtils, Fonts,{}
  152.         AppleEvents, OSA, Lists,{ PhC Feb 98 }
  153. {$IFC GENERATINGPOWERPC }
  154.         {PPCTransSkelCallProcs,}
  155.         Speech, { Philippe 27-oct-97, see CallPMouse }
  156. {$ENDC}
  157.         Devices, TextEdit, Traps, Events, Dialogs, Resources, DiskInit, {}
  158.         AppleEvents, OSUtils, EPPC, LowMem, {}
  159.         {Added for PPC callbacks:}
  160.         ColorPicker, Processes, MixedMode, AppleTalk, SoundInput,{}
  161.         QuickTimeComponents, Movies, Connections;
  162. {$ELSEC}
  163.     uses
  164.         InterfacesUI; {Glue for 4.0.2 without UPI!}
  165. {$ENDC}
  166.  
  167.     procedure SkelInit (noMasters: integer;
  168.                                     myGrowZone: ProcPtr);
  169.     procedure SkelReqdAEInit (myOAPP, myODOC, myPDOC, myQuit: ProcPtr); { Added by PhC 20/02/98 }
  170.     procedure SkelMain;
  171.     procedure SkelWhoa;
  172.     procedure SkelClobber;
  173.     function SkelMenu (theMenu: MenuHandle;
  174.                                     pSelect: ProcPtr;
  175.                                     pClobber: ProcPtr;
  176.                                     DrawBar: Boolean): Boolean;
  177.     function SkelHMenu (theMenu: MenuHandle;
  178.                                     pSelect: ProcPtr;
  179.                                     pClobber: ProcPtr): Boolean; {Added by Ingemar 22/8 -93}
  180.     procedure SkelRmveMenu (theMenu: MenuHandle);
  181.     procedure SkelApple (aboutTitle: Str255;
  182.                                     aboutProc: ProcPtr);
  183.     function SkelGetAppleMenu: MenuHandle; { Added by Phc 10/03/98 }
  184.     function SkelWindow (theWind: WindowPtr;
  185.                                     pMouse, pKey, pUpdate, pActivate, pClose, pClobber, pIdle: ProcPtr;
  186.                                     frontOnly: Boolean): Boolean;
  187.     procedure SkelRmveWind (theWind: WindowPtr);
  188. {$IFC supportDialogs }
  189.     function SkelDialog (theDialog: DialogPtr;
  190.                                     pEvent, pClose, pClobber, pFilter: ProcPtr): Boolean; {pFilter added by Ingemar 18/9-93}
  191.     procedure SkelRmveDlog (theDialog: DialogPtr);
  192. {$ENDC}
  193.     procedure SkelGrowBounds (theWind: WindowPtr;
  194.                                     hLO, vLo, hHi, vHi: integer);
  195.     procedure SkelEventMask (mask: integer);
  196.     procedure SkelGetEventMask (var mask: integer);
  197.     procedure SkelBackground (p: ProcPtr);
  198.     procedure SkelGetBackground (var p: ProcPtr);
  199.     procedure SkelEventHook (p: ProcPtr);
  200.     procedure SkelGetEventHook (var p: ProcPtr);
  201. {$IFC supportDialogs }
  202.     procedure SkelDlogMask (mask: integer);
  203.     procedure SkelGetDlogMask (var mask: integer);
  204. {$ENDC}
  205. {Two new procedures for WNE-support, added by Ingemar 12/11-93}
  206.     procedure SkelSetSleep (newSleep: Longint);
  207.     procedure SkelSetMouseRgn (newMouseRgn: RgnHandle);
  208. {Utility function, added by Ingemar 13/7-94}
  209.     function FindWindowByRefcon (theRefCon: Longint): WindowPtr;
  210. {Suspend/resume, added by Ingemar 23/7 -94}
  211.     procedure SkelSetSuspendResume (p: ProcPtr);
  212.     function SkelGetSuspendResume: ProcPtr;
  213. {Mouse moved events, added by Ingemar jan -95:}
  214.     procedure SkelSetMouseMoved (p: ProcPtr);
  215.     function SkelGetMouseMoved: ProcPtr;
  216.  
  217. implementation
  218.  
  219.     const
  220.         kHighLevelEvent = 23;
  221. {Some stuff that are here to avoid including EPPC and AppleEvents in}
  222. {Think projects, added by Ingemar 23/7 -94}
  223. {$IFC UNDEFINED THINK_PASCAL}
  224. {$ELSEC}
  225. { Stuff from AppleEvents.p }
  226.     const
  227.         keyDirectObject = '----';
  228.         typeAEList = 'list';
  229.         typeFSS = 'fss ';
  230.         errAEEventNotHandled = -1708;       { The AppleEvent was not handled by any handler }
  231.         kCoreEventClass = 'aevt';
  232.  
  233.         kAEOpenApplication = 'oapp';
  234.         kAEOpenDocuments = 'odoc';
  235.         kAEPrintDocuments = 'pdoc';
  236.         kAEQuitApplication = 'quit';
  237.  
  238.     type
  239.         AEEventHandlerUPP = UniversalProcPtr;
  240.         AEEventHandlerProcPtr = ProcPtr;
  241.         AEKeyword = packed array[1..4] of CHAR;
  242.         AEEventClass = packed array[1..4] of CHAR;
  243.         AEEventID = packed array[1..4] of CHAR;
  244.         DescType = ResType;
  245.  
  246. { tagged data, the standard AppleEvent data type }
  247.         AEDesc = record
  248.                 descriptorType: DescType;
  249.                 dataHandle: Handle;
  250.             end;
  251.  
  252.  
  253.         AEAddressDesc = AEDesc;             { an AEDesc which contains addressing data }
  254.         AEDescList = AEDesc;                { a list of AEDesc is a special kind of AEDesc }
  255.         AERecord = AEDescList;              { AERecord is a list of keyworded AEDesc }
  256.         AppleEvent = AERecord;              { an AERecord that contains an AppleEvent }
  257.  
  258.     function AEProcessAppleEvent (theEventRecord: EventRecord): OSErr;
  259.     inline
  260.         $303C, $021B, $A816;
  261.     function AEGetParamDesc (theAppleEvent: AppleEvent;
  262.                                     theAEKeyword: AEKeyword;
  263.                                     desiredType: DescType;
  264.                                     var result: AEDesc): OSErr;
  265.     inline
  266.         $303C, $0812, $A816;
  267.     function AECountItems (theAEDescList: AEDescList;
  268.                                     var theCount: LONGINT): OSErr;
  269.     inline
  270.         $303C, $0407, $A816;
  271.     function AEGetNthPtr (theAEDescList: AEDescList;
  272.                                     index: LONGINT;
  273.                                     desiredType: DescType;
  274.                                     var theAEKeyword: AEKeyword;
  275.                                     var typeCode: DescType;
  276.                                     dataPtr: Ptr;
  277.                                     maximumSize: Size;
  278.                                     var actualSize: Size): OSErr;
  279.     inline
  280.         $303C, $100A, $A816;
  281.     function NewAEEventHandlerProc (userRoutine: AEEventHandlerProcPtr): AEEventHandlerUPP;
  282.     inline
  283.         $2E9F;
  284.     function AEInstallEventHandler (theAEEventClass: AEEventClass;
  285.                                     theAEEventID: AEEventID;
  286.                                     handler: AEEventHandlerUPP;
  287.                                     handlerRefcon: LONGINT;
  288.                                     isSysHandler: BOOLEAN): OSErr;
  289.     inline
  290.         $303C, $091F, $A816;
  291.  
  292. {And from LowMem:}
  293.     function LMGetMBarHeight: Integer;
  294.     inline
  295.         $3EB8, $0BAA;            { MOVE.w $0BAA,(SP) }
  296. {$ENDC}
  297.  
  298.  
  299.     const
  300.         {mBarHeight = 20;    { menu bar height.  All window sizing }
  301.  
  302.         growZoneSize = 4000;        {  Size of memory to be freed when GrowZone Proc called }
  303.  
  304.         defaultSleep = 5;        { Added by Ingemar dec -93. SkelInit uses this value for sleep time.}
  305.                             { The programmer can change it with SkelSetSleep }
  306.  
  307. {    This window zooming stuff may need to be removed if you use the new Rom libraries        }
  308. {    if not, then you can add zooming without the overhead of the new Rom libs.  See TrackBox    }
  309. {     routine also.                                                                                            }
  310.  
  311. {    Window and Menu handler types, constants, variables.}
  312.  
  313. {    whList and mhList are the lists of window and menu handlers.}
  314. {    whClobOnRmve and mhClobOnRmve are true if the handler disposal proc}
  315. {    is to be called when a handler is removed.  They are temporarily set}
  316. {    false when handlers are installed for windows or menus that already}
  317. {    have handlers - the old handler is removed WITHOUT calling the}
  318. {    disposal proc.}
  319.  
  320. {    Default lower limits on window sizing of 80 pixels both directions is}
  321. {    sufficient to allow text windows room to draw a grow box and scroll}
  322. {    bars without having the thumb and arrows overlap.  These values may}
  323. {    be changed if such a constraint is undesirable with SkelGrowBounds.}
  324. {    Default upper limits are for the Macintosh, not the Lisa, but are set}
  325. {    per machine in SkelInit.}
  326.  
  327.     type
  328.         WHandlerPtr = ^WHandler;
  329.         WHandlerHnd = ^WHandlerPtr;
  330.         WHandler = record
  331.                 whWind: WindowPtr;    {window/dialog to be handled    }
  332.                 whClobber: ProcPtr;    { data structure disposal proc    }
  333.                 whMouse: ProcPtr;        { mouse-click handler proc        }
  334.                 whKey: ProcPtr;        { key-click handler proc            }
  335.                 whUpdate: ProcPtr;        { update handler proc                }
  336.                 whActivate: ProcPtr;    { activate event handler proc    }
  337.                 whClose: ProcPtr;        { close "event" handler proc        }
  338.                 whIdle: ProcPtr;            { main loop proc                    }
  339. {$IFC supportDialogs }
  340.                 whEvent: ProcPtr;        { dialog event proc                }
  341.                 whFilter: ProcPtr;        { dialog filter proc ADDED BY INGEMAR 18/9 -93}
  342. {$ENDC }
  343.                 whHasGrow: Boolean;    { can window grow?                }
  344.                 whGrow: Rect;            { limits on window sizing        }
  345.                 whSized: Boolean;        { true = window was resized    }
  346.                 whFrontOnly: Boolean;    { true = idle only when active    }
  347.                 whNext: WHandlerHnd;            { next window handler            }
  348.             end;
  349.  
  350.         MHandlerPtr = ^MHandler;
  351.         MHandlerHnd = ^MHandlerPtr;
  352.  
  353.         MHandler = record
  354.                 mhID: integer;                { menu id                                    }
  355.                 mhSelect: ProcPtr;            { item selection handler proc            }
  356.                 mhClobber: ProcPtr;        { menu disposal handler proc            }
  357.                 mhNext: MHandlerHnd;        { next menu handler                        }
  358.             end;
  359.  
  360.     var
  361.         whList: WHandlerHnd;                { list of menu handlers }
  362.         whClobOnRmve: Boolean;
  363.         growRect: Rect;
  364.         mhList: MHandlerHnd;
  365.         mhClobOnRmve: Boolean;
  366.  
  367. {    Variables for default Apple menu handler.  appleID is set to 1 if}
  368. {    SkelApple is called and is the id of the Apple menu, appleAboutProc}
  369. {    is the procedure to execute if there is an About... item and it's}
  370. {    chosen from the Apple menu.  If doAbout is true, then the menu}
  371. {    contains the About... item, otherwise it's just desk accessories.}
  372.  
  373.         appleMenu: MenuHandle;
  374.         appleID: integer;
  375.         appleAboutProc: ProcPtr;
  376.         doAbout: Boolean;
  377.  
  378. {    Miscellaneous}
  379.  
  380. {    screenPort points to the window manager port.}
  381.  
  382. {    doneFlag determines when SkelMain returns.  It is set by calling}
  383. {    SkelWhoa(), which the host does to request a halt.}
  384.  
  385. {    pBkgnd points to a background procedure, to be run during event}
  386. {    processing.  Set it with SkelBackground.  If nil, there's no}
  387. {    procedure.}
  388.  
  389. {    pEvent points to an event-inspecting hook, to be run whenever an}
  390. {    event occurs.  Set it with SkelEventHook.  If nil, there's no}
  391. {    procedure.}
  392.  
  393. {    eventMask controls the event types requested in the GetNextEvent}
  394. {    call in SkelMain.}
  395.  
  396. {    diskInitPt is the location at which the disk initialization dialog}
  397. {    appears, if an uninitialized disk is inserted.}
  398.  
  399.         screenPort: GrafPtr;
  400.         doneFlag: integer;
  401.         pBkgnd: ProcPtr;
  402.         pEvent: ProcPtr;
  403.         eventMask: integer;
  404.         diskInitPt: Point;
  405.  
  406. {Added by Ingemar 12/11-93, for WNE-support:}
  407.         WNEImplemented: Boolean;
  408.         sleepTicks: Longint;
  409.         mouseRgn: rgnHandle;
  410. {…and later, for suspend/resume support:}
  411.         gSuspendResumeHandler: ProcPtr;
  412.         gMouseMovedHandler: ProcPtr;
  413. {For proper handling of suspend/resume:}
  414.         gMultiFinderAware: Boolean;
  415.  
  416. {$IFC supportDialogs }
  417.  
  418. {    Events that are passed to dialogs.  Others are ignored.}
  419. {    Standard mask passes , mousedown, keydown, autokey, update,}
  420. {    activate and null events.  Null events are controlled by bit 0.}
  421.  
  422.         dlogEventMask: integer;
  423. {$ENDC}
  424.         pEventflag: Boolean;
  425.  
  426. {    "caching" global variables.  previous version would search down the window }
  427. {    list for every event it found.  Now, if the event happened to the same window }
  428. {    as last time, GetWDHandler will just do a simple compare }
  429. {    and return the last window handler.  This speeds up multiple window applications }
  430. {    immensely, at only a slight cost when you activate a new window (one }
  431. {    compare!)  If you don't like it, use the old version. }
  432.  
  433.         oldWindow: WindowPtr;
  434.         oldWDHandler: WHandlerHnd;
  435.  
  436. {    Global for built in "Grow Zone" function  }
  437.  
  438.         safetyHandle: Handle;
  439.  
  440.         myDitl: packed array[0..100] of byte;
  441.  
  442. { For core apple events support /PhC 20/02/98 }
  443.         oappProc, odocProc, pdocProc, quitProc: ProcPtr;
  444.  
  445. { Rather than including the entire new ROM libraries, with all the other stuff you might not use    }
  446. { I've instead included just the Zoom box stuff here.  Depending on your status, you can either    }
  447. { leave things as they are, and only use zooming from the new Rom libs, or comment out the        }
  448. { calls, and include the new Rom libraries if you want to incorporate other new Rom calls        }
  449.  
  450.  
  451. { -------------------------------------------------------------------- }
  452. {                        Internal (private) Routines                                    }
  453. { -------------------------------------------------------------------- }
  454.  
  455.  
  456.  
  457. {    Get handler associated with user or dialog window.}
  458. {    Return nil if window doesn't belong to any known handler.}
  459. {    This routine is absolutely fundamental to TransSkel.}
  460.  
  461.     function GetWDHandler (theWind: WindowPtr): WHandlerHnd;
  462.  
  463.         var
  464.             h: WHandlerHnd;
  465.     begin
  466.         h := WhList;
  467.         GetWDHandler := nil;
  468.         if theWind = oldWindow then            {  caching code     }
  469.             GetWDHandler := oldWDHandler
  470.         else
  471.             while h <> nil do
  472.                 if h^^.whWind = theWind then begin
  473.                     oldWindow := theWind;            { Load in new values for new window }
  474.                     oldWDHandler := h;
  475.                     GetWDHandler := h;
  476.                     h := nil;
  477.                 end
  478.                 else
  479.                     h := WHandlerHnd(h^^.whNext);
  480.     end;
  481.  
  482. { Get Handler associated with user window.  Return nil if window doesn't}
  483. {  have a Handler. }
  484.  
  485.     function GetWHandler (theWind: WindowPtr): WHandlerHnd;
  486.  
  487.         var
  488.             h: WHandlerHnd;
  489.             myPeek: WindowPeek;
  490.  
  491.     begin
  492. {BUG FIXED by Ingemar 19/9-93. This function retured garbage when passed a dialog}
  493.         h := GetWDHandler(theWind);
  494.         myPeek := WindowPeek(theWind);
  495.         GetWHandler := nil; {default, moved up by Ingemar}
  496.         if h <> nil then begin
  497.             if mypeek^.windowKind <> dialogKind then
  498.                 GetWHandler := h;
  499.         end;
  500.     end;
  501.  
  502. {$IFC supportDialogs }
  503.  
  504. {    Get handler associated with dialog window.}
  505. {    Return nil if window doesn't belong to any known handler.}
  506.  
  507.     function GetDHandler (theDialog: WindowPtr): WHandlerHnd;
  508.  
  509.         var
  510.             h: WHandlerHnd;
  511.             myPeek: WindowPeek;
  512.  
  513.     begin
  514. {BUG FIXED by Ingemar 19/9-93. This function retured garbage when passed a non-dialog}
  515. {BUG FIXED by Philippe 26/11/97. This function dereferenced a nil pointer if passed a}
  516. {                                nil Window pointer.}
  517.         GetDHandler := nil; {default - moved up by Ingemar - Moved at beginning by Philippe}
  518.         if (theDialog <> nil) then begin { Added by Philippe }
  519.             h := GetWDHandler(theDialog);
  520.             myPeek := WindowPeek(theDialog);
  521.             if h <> nil then begin
  522.                 if mypeek^.windowKind = dialogKind then
  523.                     GetDHandler := h;
  524.             end;
  525.         end;
  526.     end;
  527. {$ENDC}
  528.  
  529. {Two new routines added by Ingemar 12/11-93 for WNE support:}
  530.     procedure SkelSetSleep (newSleep: Longint);
  531.     begin
  532.         sleepTicks := newSleep;
  533.     end;
  534.     procedure SkelSetMouseRgn (newMouseRgn: RgnHandle);
  535.     begin
  536.         mouseRgn := newMouseRgn;
  537.     end;
  538.  
  539. {Utility routine added by Ingemar july 1994. Finds a window in the window list that has the same}
  540. {refCon as the value passed. This is useful for programs where several windows share window handlers.}
  541. {(To be precise, i needed it for a program where I have several connections to other Macs over Appletalk.)}
  542.     function FindWindowByRefcon (theRefCon: Longint): WindowPtr;
  543.         var
  544.             h: WHandlerHnd;
  545.     begin
  546.         FindWindowByRefcon := nil;
  547.         h := WhList;
  548.         while h <> nil do
  549.             if WindowPeek(h^^.whWind)^.refCon = theRefCon then begin
  550.                 FindWindowByRefcon := h^^.whWind;
  551.                 exit(FindWindowByRefcon);
  552.             end
  553.             else
  554.                 h := WHandlerHnd(h^^.whNext);
  555.     end;
  556.  
  557.     procedure SkelSetSuspendResume (p: ProcPtr);
  558.     begin
  559.         gSuspendResumeHandler := p;
  560.     end;
  561.     function SkelGetSuspendResume: ProcPtr;
  562.     begin
  563.         SkelGetSuspendResume := gSuspendResumeHandler;
  564.     end;
  565.  
  566.     procedure SkelSetMouseMoved (p: ProcPtr);
  567.     begin
  568.         gMouseMovedHandler := p;
  569.     end;
  570.     function SkelGetMouseMoved: ProcPtr;
  571.     begin
  572.         SkelGetMouseMoved := gMouseMovedHandler;
  573.     end;
  574.  
  575.  
  576. {**** Callbacks ****}
  577.  
  578. {The following procedures are Pascal "glue" that allows Pascal to call a Procedure    }
  579. { from a ProcPtr.  It is similar to (*p) () construct used in the C dialect.  Different    }
  580. { procedures are necessary for the reason of Pascal's strongly typed parameter        }
  581. { list.  Fortunately, there are not too many calls which use different param lists        }
  582.  
  583. {Change by Ingemar 1997:}
  584. {To support PPC without extra C glue, I implement the callbacks through the}
  585. {callbacks that are defined in the Toolbox.}
  586.  
  587. {$IFC GENERATINGPOWERPC}
  588. {Note: I know I would save some time by doing the New***Proc calls once and for all}
  589. {when the pointers are installed by the main program, but... that would mean changes}
  590. {all over the code. Some other time. /Ingemar}
  591.     var
  592.         tempUPP: UniversalProcPtr;
  593.  
  594. { Note: in this procedure I have changed "DataHCompletion*" to "SpeechPhoneme*" since for unknown }
  595. { reasons the former is not in the MW Pascal.PPC.lib library. However, the definition is the same: }
  596. { one 4-byte param, one 4-byte and one 2-byte param. /Philippe }
  597.     procedure CallPMouse (thePoint: Point;
  598.                                     theTime: longint;
  599.                                     theMods: integer;
  600.                                     myProc: ProcPtr);
  601.     begin
  602.         tempUPP := NewSpeechPhonemeProc(SpeechPhonemeProcPtr(myProc)); {NewDataHCompletionProc}
  603. {DataHCompletionProcPtr}
  604.         {CallDataHCompletionProc}
  605.         CallSpeechPhonemeProc(SpeechChannel(thePoint), theTime, theMods, tempUPP);{Ptr}
  606.         DisposePtr(Ptr(tempUPP));
  607.     end;
  608.     procedure CallPKey (theChar: char;
  609.                                     theMods: integer;
  610.                                     myProc: ProcPtr);
  611.     begin
  612.         tempUPP := NewAttnRoutineProc(AttnRoutineProcPtr(myProc));
  613.         CallAttnRoutineProc(Integer(theChar), theMods, tempUPP); {Går det bra med char så där?}
  614.         DisposePtr(Ptr(tempUPP));
  615.     end;
  616.     procedure CallPEvent (theitem: integer;
  617.                                     var theEvent: EventRecord;
  618.                                     myProc: ProcPtr);
  619.     begin
  620.         tempUPP := NewMoviesErrorProc(MoviesErrorProcPtr(myProc));
  621.         CallMoviesErrorProc(theitem, LONGINT(@theEvent), tempUPP); {Går det bra med var?}
  622.         DisposePtr(Ptr(tempUPP));
  623.     end;
  624.     function CallOtherEvent (var theEvent: EventRecord;
  625.                                     myProc: ProcPtr): Boolean;
  626.     begin
  627.         tempUPP := NewUserEventProc(UserEventProcPtr(myProc));
  628.         CallOtherEvent := CallUserEventProc(theEvent, tempUPP);
  629.         DisposePtr(Ptr(tempUPP));
  630.     end;
  631.     procedure CallPBoolean (myBool: Boolean;
  632.                                     myProc: ProcPtr);
  633.     begin
  634.         tempUPP := NewSoundProc(SoundProcPtr(myProc));
  635.         CallSoundProc(Integer(myBool), tempUPP); {Går detta med Boolean?}
  636.         DisposePtr(Ptr(tempUPP));
  637.     end;
  638.     procedure CallPInt (myInt: integer;
  639.                                     myProc: ProcPtr);
  640.     begin
  641.         tempUPP := NewSoundProc(SoundProcPtr(myProc));
  642.         CallSoundProc(myInt, tempUPP);
  643.         DisposePtr(Ptr(tempUPP));
  644.     end;
  645.     procedure CallPMenu (myMenu: MenuHandle;
  646.                                     myProc: ProcPtr);
  647.     begin
  648.         tempUPP := NewSICompletionProc(SICompletionProcPtr(myProc));
  649.         CallSICompletionProc(SPBPtr(myMenu), tempUPP);
  650.         DisposePtr(Ptr(tempUPP));
  651.     end;
  652.     procedure CallPnoarg (myProc: ProcPtr);
  653.     begin
  654.         tempUPP := NewFKEYProc(FKEYProcPtr(myProc));
  655.         CallFKEYProc(tempUPP);
  656.         DisposePtr(Ptr(tempUPP));
  657.     end;
  658. { Added by PhC 02/98 }
  659.     function CallFnoarg (myProc: ProcPtr): Boolean;
  660.     begin
  661.         tempUPP := NewListClickLoopProc(ListClickLoopProcPtr(myProc));
  662.         CallFnoarg := CallListClickLoopProc(tempUPP);
  663.         DisposePtr(Ptr(tempUPP));
  664.     end;
  665.     function CallFLongInt (l: LongInt;
  666.                                     myProc: ProcPtr): OSErr;
  667.     begin
  668.         tempUPP := NewOSAActiveProc(OSAActiveProcPtr(myProc));
  669.         CallFLongInt := CallOSAActiveProc(l, tempUPP);
  670.         DisposePtr(Ptr(tempUPP));
  671.     end;
  672.     procedure CallPfilter (theDialog: DialogPtr;
  673.                                     var theEvent: EventRecord;
  674.                                     var result: Boolean;
  675.                                     myProc: ProcPtr);
  676.     begin
  677.         tempUPP := NewConnectionSearchCallBackProc(ConnectionSearchCallBackProcPtr(myProc));
  678.         CallConnectionSearchCallBackProc(ConnHandle(theDialog), Ptr(@theEvent), LONGINT(@result), tempUPP);{}
  679.         DisposePtr(Ptr(tempUPP));
  680.     end;
  681. {$ELSEC}
  682. {68k}
  683.     procedure CallPMouse (thePoint: Point;
  684.                                     theTime: longint;
  685.                                     theMods: integer;
  686.                                     myProc: ProcPtr);
  687.     inline
  688.         $205f, $4e90;
  689.  
  690.     procedure CallPKey (theChar: char;
  691.                                     theMods: integer;
  692.                                     myProc: ProcPtr);
  693.     inline
  694.         $205f, $4e90;
  695.  
  696.     procedure CallPEvent (theitem: integer;
  697.                                     var theEvent: EventRecord;
  698.                                     myProc: ProcPtr);
  699.     inline
  700.         $205f, $4e90;
  701.  
  702.     function callotherEvent (var theEvent: EventRecord;
  703.                                     myProc: ProcPtr): Boolean;
  704.     inline
  705.         $205f, $4e90;
  706.  
  707. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  708. { both of them.                                                                            }
  709.     procedure CallPBoolean (myBool: Boolean;
  710.                                     myProc: ProcPtr);
  711.     inline
  712.         $205f, $4e90;
  713.  
  714.     procedure CallPInt (myInt: integer;
  715.                                     myProc: ProcPtr);
  716.     inline
  717.         $205f, $4e90;
  718.  
  719. { Handle removal of menus.     }
  720.     procedure CallPMenu (myMenu: MenuHandle;
  721.                                     myProc: ProcPtr);
  722.     inline
  723.         $205f, $4e90;
  724.  
  725. { For all the Procedures that are called with no arguments                            }
  726.     procedure CallPnoarg (myProc: ProcPtr);
  727.     inline
  728.         $205f, $4e90;
  729.  
  730. { Added by PhC 02/98 }
  731.     function CallFnoarg (myProc: ProcPtr): Boolean;
  732.     inline
  733.         $205f, $4e90;
  734.     function CallFLongint (l: LongInt;
  735.                                     myProc: ProcPtr): OSErr;
  736.     inline
  737.         $205f, $4e90;
  738.  
  739. {ADDED BY INGEMAR 18/9-93 to support new dialog filters}
  740. {IS IT POSSIBLE to use this for functions?}
  741.     procedure CallPfilter (theDialog: DialogPtr;
  742.                                     var theEvent: EventRecord;
  743.                                     var result: Boolean;
  744.                                     myProc: ProcPtr);
  745.     inline
  746.         $205f, $4e90;
  747. {$ENDC}
  748.  
  749.  
  750.  
  751. {    General menu-handler.  Just passes selection to the handler's}
  752. {    select routine.  If the select routine is nil, selecting items from}
  753. {    the menu is a nop.}
  754.  
  755.     procedure DoMenuCommand (command: longint);
  756.  
  757.         var
  758.             menu: integer;
  759.             item: integer;
  760.             mh: MHandlerHnd;
  761.             p: ProcPtr;
  762.  
  763.     begin
  764.         menu := HiWord(command);
  765.         item := LoWord(command);
  766.         mh := mhList;
  767.         while (mh <> nil) do begin
  768.             p := mh^^.mhSelect;
  769.             if ((menu = mh^^.mhID) and (p <> nil)) then begin
  770.                 CallPInt(item, p);
  771.                 mh := nil;
  772.             end
  773.             else
  774.                 mh := mh^^.mhNext;
  775.         end;
  776.         HiliteMenu(0);
  777.     end;
  778.  
  779. {    Apple menu handler}
  780.  
  781. {    DoAppleItem:  If the first item was chosen, and there's an "About..."}
  782. {    item, call the procedure associated with it (if not nil).  If there}
  783. {    is no "About..." item or the item was not the first one, then open}
  784. {    the associated desk accessory.  The port is saved and restored}
  785. {    because OpenDeskAcc does not always preserve it correctly.}
  786.  
  787. {    DoAppleClobber disposes of the Apple menu.}
  788.  
  789.     procedure DoAppleItem (item: integer);
  790.  
  791.         var
  792.             curPort: GrafPtr;
  793.             str: Str255;
  794.             ignore: integer;
  795.             h: Handle;
  796.  
  797.     begin
  798.         if doAbout and (item = 1) then begin
  799.             if appleAboutProc <> nil then
  800.                 CallPnoarg(appleAboutProc);
  801.         end
  802.         else begin
  803.             GetPort(curPort);
  804.             GetMenuItemText(appleMenu, item, str);
  805.             SetResLoad(false);
  806.             h := GetNamedResource('DRVR', str);
  807.             SetResLoad(true);
  808.             if h <> nil then begin
  809.                 ReserveMem(GetResourceSizeOnDisk(h) + $1000);
  810.                 ignore := OpenDeskAcc(str);
  811.             end;
  812.             SetPort(curPort);
  813.         end;
  814.     end;
  815.  
  816.     procedure DoAppleClobber;
  817.     begin
  818.         DisposeMenu(appleMenu);
  819.     end;
  820.  
  821. { --------------------------------------------------------------------     }
  822. {                        Window-handler routing routines                            }
  823. {                                                                                        }
  824. {    Each routine sets the port to the handler's window before executing        }
  825. {    the handler procedure.                                                            }
  826. { --------------------------------------------------------------------     }
  827.  
  828.  
  829. {    Pass local mouse coordinates, click time, and the modifiers flag}
  830. {    word to the handler.  Should not be necessary to set the port, as}
  831. {       the click is passed to the active window's hander. }
  832.  
  833.     procedure DoMouse (h: WHandlerHnd;
  834.                                     theEvent: EventRecord);
  835.  
  836.         var
  837.             p: ProcPtr;
  838.             thePt: Point;
  839.  
  840.     begin
  841.         if (h <> nil) then begin
  842.             p := h^^.whMouse;
  843.             if p <> nil then begin
  844.                 thePt := theEvent.where;
  845.                 GlobalToLocal(thePt);
  846.                 CallPMouse(thePt, theEvent.when, theEvent.modifiers, p);
  847.             end;
  848.         end;
  849.     end;
  850.  
  851. {    Pass the character and the modifiers flag word to the handler.}
  852. {    Should not be necessary to set the port, as the  click is passed to the}
  853. {    active window's handler. }
  854.  
  855.     procedure DoKey (h: WHandlerHnd;
  856.                                     ch: char;
  857.                                     mods: integer);
  858.         var
  859.             p: ProcPtr;
  860.  
  861.     begin
  862.         if h <> nil then begin
  863.             p := h^^.whKey;
  864.             if p <> nil then
  865.                 CallPKey(ch, mods, p);
  866.         end;
  867.     end;
  868.  
  869. {    Call the window updating procedure, passing to it an indicator whether the}
  870. {    window has been resized or not.  Then clear the flag, assuming the update}
  871. {    proc took whatever action was necessary to respond to resizing.}
  872. {}
  873. {    If the handler doesn't have any update proc, the Begin/EndUpdate stuff}
  874. {    is still done, to clear the update region.  Otherwise the Window Manager }
  875. {    will keep generating update events for the window, stalling updates of}
  876. {    other windows.    }
  877.  
  878. {    Make sure to save and restore the port, as it's not always the active window}
  879. {    that's updated.    }
  880.  
  881.     procedure DoUpdate (h: WHandlerHnd);
  882.  
  883.         var
  884.             rh: WhandlerHnd;
  885.             p: ProcPtr;
  886.             updPort, tmpPort: GrafPtr;
  887.  
  888.     begin
  889.         rh := h;
  890.         if rh <> nil then begin
  891.             GetPort(tmpPort);
  892.             updPort := rh^^.whWind;
  893.             SetPort(updPort);
  894.             BeginUpdate(updPort);
  895.             p := rh^^.whUpdate;
  896.             if p <> nil then begin
  897.                 CallPBoolean(rh^^.whSized, p);
  898.                 rh^^.whSized := false;
  899.             end;
  900.             EndUpdate(updPort);
  901.             SetPort(tmpPort);
  902.         end;
  903.     end;
  904.  
  905. {    Pass activate/deactivate notification to handler.  On activate, set the port to}
  906. {    the window coming active    }
  907.  
  908.     procedure DoActivate (h: WHandlerHnd;
  909.                                     active: Boolean);
  910.  
  911.         var
  912.             p: ProcPtr;
  913.             savePort: GrafPtr;
  914.  
  915.     begin
  916.         if h <> nil then begin
  917. {Change by Ingemar dec 94: To make multi-window handlers possible/practical, we must be told what window}
  918. {is the current one, preferrably by making that the current port. This is a slight modification of the port-}
  919. {setting model of TS 2.0, but necessary for TransDisplay to work properly.}
  920.             if not active then
  921.                 GetPort(savePort);
  922. {if active then}
  923.             SetPort(h^^.whWind);
  924.             p := h^^.whActivate;
  925.             if p <> nil then
  926.                 CallPBoolean(active, p);
  927.             if not active then
  928.                 SetPort(savePort);
  929.         end
  930.     end;
  931.  
  932. {    Execute a window handler's close proc.  The close box for handlers}
  933. {    for temp windows that want to remove themselves when the window}
  934. {    is closed can call SkelRmveWind to dispose of the window}
  935. {    and remove the handler from the window handler list.  Thus, windows}
  936. {    may be dynamically created and destroyed without filling up the}
  937. {    handler list with a bunch of invalid handlers.}
  938.  
  939. {    If the handler doesn't have a close proc, just hide the window.}
  940. {    The host should provide some way of reopening the window (perhaps}
  941. {    a menu selection).  Otherwise the window will be lost from user}
  942. {    control if it is hidden, since it won't receive user-initiated events.}
  943.  
  944. {    Since the close box of only the active window may be clicked, it}
  945. {    is not necessary to set the port . }
  946.  
  947. {    This is called both for regular and dialog windows.}
  948.  
  949.     procedure DoClose (h: WHandlerHnd);
  950.  
  951.         var
  952.             rh: WHandlerHnd;
  953.             p: ProcPtr;
  954.     begin
  955.         rh := h;
  956.         if rh <> nil then begin
  957.             p := rh^^.whClose;
  958.             if (p <> nil) then
  959.                 CallPnoarg(p)
  960.             else
  961.                 HideWindow(rh^^.whWind);
  962.         end;
  963.     end;
  964.  
  965. {    Execute a window Handler's clobber proc.  This is called both for regular and dialog windows.}
  966. {    Must save, set and restore port, since any window (not just active one) may be clobbered    }
  967. {    at any time.}
  968. {}
  969. {    Don't need to check whether handler is nil, as in other handler procedures, since this is only}
  970. {    called by SkelRmveWind with a known valid handler.     }
  971.  
  972.     procedure DoClobber (h: WHandlerHnd);
  973.  
  974.         var
  975.             p: ProcPtr;
  976.             curPort: Grafptr;
  977.     begin
  978.         if (h <> nil) then begin
  979.             GetPort(curPort);
  980.             SetPort(h^^.whWind);
  981.             p := h^^.whClobber;
  982.             if p <> nil then
  983.                 CallPnoarg(p);
  984.             SetPort(curPort);
  985.         end;
  986.     end;
  987.  
  988. {$IFC supportDialogs }
  989.  
  990. {    Handle event if it's for a dialog.  The event must be one of}
  991. {    those that is passed to dialogs according to dlogEventMask.}
  992. {    This mask can be set so that disk-inserts, for instance, don't}
  993. {    get eaten up.}
  994.  
  995.     function DoDialog (theEvent: EventRecord): Boolean;
  996.  
  997.         var
  998.             dh: WHandlerHnd;
  999.             theDialog: DialogPtr;
  1000.             what: integer;
  1001.             item: integer;
  1002.             tmpPort: GrafPtr;
  1003.             testme: Longint;
  1004.             hasfilter, filtered: Boolean;
  1005.  
  1006.     begin
  1007.  
  1008. {    handle command keys before they get to IsDialogEvent}
  1009.  
  1010.         what := theEvent.what;
  1011.         testme := BitShift(longint(1), what);
  1012.         testme := BitAnd(testme, longint(dlogEventMask));
  1013.         if (((what = keydown) or (what = autokey)) and (BitAnd(theEvent.modifiers, cmdkey) <> 0)) then
  1014. { Bugfix by Ingemar above! }
  1015.             begin
  1016.             DoMenuCommand(MenuKey(Char(BitAnd(theEvent.message, charCodeMask))));
  1017.             DoDialog := true;
  1018.         end
  1019. {Filter procedure, Added by Ingemar 18/9 -93:}
  1020.         else begin
  1021. {Check if theDialog has whFilter!}
  1022. {Bugfix 941026: I used FrontWindow, which was really silly since that won't work}
  1023. {for update events!}
  1024.  
  1025.             if (what = updateEvt) or (what = activateEvt) then
  1026.                 theDialog := DialogPtr(theEvent.message)
  1027.             else
  1028.                 theDialog := FrontWindow;
  1029.  
  1030.             dh := WHandlerHnd(GetDHandler(theDialog));
  1031.             filtered := false;
  1032.             hasfilter := dh <> nil;
  1033.             if hasfilter then
  1034.                 hasfilter := dh^^.whFilter <> nil;
  1035.             if hasfilter then
  1036.                 CallPFilter(theDialog, theEvent, filtered, dh^^.whFilter);
  1037.             DoDialog := filtered;
  1038.             if not filtered then
  1039. {end of filter proc handling}
  1040. {else}
  1041.                 if testme > 0 then
  1042.                     if IsDialogEvent(theEvent) then begin
  1043.                         if DialogSelect(theEvent, theDialog, item) then begin
  1044.                             dh := WHandlerHnd(GetDHandler(theDialog));
  1045.                             if (dh <> nil) then
  1046.                                 if (dh^^.whEvent <> nil) then begin
  1047.                                     GetPort(tmpPort);
  1048.                                     SetPort(theDialog);
  1049.                                     CallPEvent(item, theEvent, dh^^.whEvent);
  1050.                                     SetPort(tmpPort);
  1051.                                 end;
  1052.                         end;
  1053.                         DoDialog := true;
  1054.                     end
  1055.                     else
  1056.                         DoDialog := false;
  1057.         end; {to match begin added with filter above}
  1058.     end;
  1059. {$ENDC}
  1060.  
  1061. { -------------------------------------------------------------------- }
  1062. {                            Event-handling routines                        }
  1063. { -------------------------------------------------------------------- }
  1064.  
  1065. {    Have either sized or zoomed the window.  Invalidate it to force}
  1066. {    an update and set the 'resized' flag in the window handler true.}
  1067. {    The port is assumed to be set to the port that changed size.        }
  1068.  
  1069.     procedure TriggerUpdate (h: WHandlerHnd;
  1070.                                     thePort: GrafPtr);
  1071.  
  1072.     begin
  1073.         InvalRgn(thePort^.visRgn);
  1074. {Changed by Ingemar 1/4-94. Was: InvalRect(thePort^.portRect);}
  1075. {This is ok for rectangular windows, but all windows aren't rectangular!}
  1076.         if (h <> nil) then begin
  1077.             h^^.whSized := true;
  1078.         end;
  1079.     end;
  1080.  
  1081. {    Size a window.  If the window has a handler, use the grow limits}
  1082. {    in the handler record, otherwise use the defaults.}
  1083.  
  1084. {    The portRect is invalidated to force an update event.    The handler's}
  1085. {    update procedure should check the parameter passed to it to check}
  1086. {    whether the window has changed size, if it needs to adjust itself to}
  1087. {    the new size.  THIS IS A CONVENTION.  Update procs must notice grow}
  1088. {    "events", there is no procedure specifically for such events.}
  1089.  
  1090. {    The clipping rectangle is not reset.  If the host application}
  1091. {    keeps the clipping set equal to the portRect or something similar,}
  1092. {    then it will have to arrange to treat window growing with more}
  1093. {    care.}
  1094. {}
  1095. {    Since the grow region of only the active window may be clicked, it should}
  1096. {    not be necessary to set the port.}
  1097.  
  1098.     procedure DoGrow (h: WHandlerHnd;
  1099.                                     thePort: GrafPtr;
  1100.                                     StartPt: Point);
  1101.  
  1102.         var
  1103.             r: Rect;
  1104.             growRes: longint;
  1105.  
  1106.     begin
  1107.         if (h <> nil) then begin
  1108.             r := h^^.whGrow;
  1109.         end
  1110.         else
  1111.             r := growRect;
  1112.         growRes := GrowWindow(thePort, startPt, r);
  1113.         if growRes <> 0 then begin
  1114.             SizeWindow(thePort, LoWord(growRes), HiWord(growRes), false);
  1115.             TriggerUpdate(h, thePort);
  1116.         end;
  1117.     end;
  1118.  
  1119.  
  1120. {    Zoom the current window.  Very similar to DoGrow}
  1121. {    Since the zoombox of only the active window may be clicked, it should not be necessary}
  1122. {    to set the port.    }
  1123.  
  1124.     procedure DoZoom (h: WHandlerHnd;
  1125.                                     thePort: GrafPtr;
  1126.                                     partcode: integer);
  1127.  
  1128.     begin
  1129.         ZoomWindow(thePort, partcode, false);
  1130.         TriggerUpdate(h, thePort);
  1131.     end;
  1132.  
  1133. {    General event handler}
  1134.  
  1135.     procedure DoEvent (theEvt: EventRecord);
  1136.  
  1137.         var
  1138.             theEvent: EventRecord;
  1139.             evtPt: Point;
  1140.             evtPort: GrafPtr;
  1141.             evtPart: integer;
  1142.             evtChar: char;
  1143.             evtMods: integer;
  1144.             h: WHandlerHnd;
  1145.             r: Rect;
  1146.             ignore: integer;
  1147.  
  1148.     begin
  1149.         theEvent := theEvt;
  1150. {$IFC supportDialogs }
  1151.         if not DoDialog(theEvent) then
  1152. {$ENDC}
  1153.             begin
  1154.             evtPt := theEvent.where;
  1155.             evtMods := theEvent.modifiers; {Bug fixed by Ingemar 941027 - this statement was missing}
  1156.             case theEvent.what of
  1157.                 nullEvent: 
  1158.                     ;
  1159.  
  1160. {    Mouse click.  Get the window that the click occurred in, and the}
  1161. {    part of the window.    Get WDHandler is called here, not GetWHandler, since}
  1162. {    we need the handler for a window which might turn out to be a dialog window,}
  1163. {    e.g., if the click is in a close box.}
  1164.  
  1165.                 mouseDown:  begin
  1166.                     evtPart := FindWindow(evtPt, evtPort);
  1167.                     h := GetWDHandler(evtPort);
  1168.                     case evtPart of
  1169.  
  1170. {    Click in a desk accessory window.  Pass back to the system.}
  1171.  
  1172.                         inSysWindow: 
  1173.                             SystemClick(theEvent, evtPort);
  1174.  
  1175. {    Click in menu bar.  Track the mouse and execute selected command,}
  1176. {    if any.}
  1177.  
  1178.                         inMenuBar: 
  1179.                             DoMenuCommand(MenuSelect(evtPt));
  1180.  
  1181. {    Click in grow box.  Resize window.}
  1182.  
  1183.                         inGrow: 
  1184.                             DoGrow(h, evtPort, evtPt);
  1185.  
  1186. {    Click in title bar.  Drag the window around.  Leave at least}
  1187. {    4 pixels visible in both directions.    Bug fix: The window, if not front, is}
  1188. {    selected first to make sure it's at least activated (unless the command key is down - see Inside}
  1189. {    Macintosh).  DragWindow seems to call StillDown first, so that clicks in drag regions while}
  1190. {    machine is busy don't otherwise bring window to front if the mouse is already up by the time}
  1191. {    DragWindow is called.}
  1192.  
  1193.                         inDrag:  begin
  1194.                             if (evtPort <> FrontWindow) and (BitAnd(evtmods, cmdKey) = 0) then
  1195.                                 SelectWindow(evtPort);
  1196.                             r := screenPort^.portRect;
  1197.                             r.top := r.top + LMGetMBarHeight;        { Skip down past menu bar    }
  1198.                             InsetRect(r, 4, 4);
  1199.                             DragWindow(evtPort, evtPt, r);
  1200.  
  1201. {Added by Ingemar jan -95:}
  1202. {Window has moved. The app can't know this, but it is of interest only for the mouse-moved}
  1203. {event handling – so let's call it!}
  1204.                             if gMouseMovedHandler <> nil then
  1205.                                 CallPNoArg(gMouseMovedHandler);
  1206.                         end;
  1207.  
  1208. {    Click in close box.  Call the close proc if the window has one.}
  1209.  
  1210.                         inGoAway: 
  1211.                             if (TrackGoAway(evtPort, evtPt)) then
  1212.                                 DoClose(GetWDHandler(evtPort));
  1213.  
  1214. {    Click in content region.  If the window wasn't frontmost (active),}
  1215. {    just select it, otherwise pass the click to the window's mouse}
  1216. {    click handler.}
  1217.  
  1218.                         inContent: 
  1219.                             if (evtPort <> FrontWindow) then
  1220.                                 SelectWindow(evtPort)
  1221.                             else
  1222.                                 DoMouse(h, theEvent);
  1223.  
  1224. {    Click in zoom box.  Track the click and then zoom the window if}
  1225. {    necessary}
  1226.  
  1227.                         inZoomin, inZoomOut: 
  1228.                             if (TrackBox(evtPort, evtPt, evtPart)) then
  1229.                                 DoZoom(h, evtport, evtPart);
  1230.                         otherwise
  1231.                             ;
  1232.                     end;{mousedown}
  1233.                 end;
  1234.  
  1235. {    Key event.  If the command key was down, process as menu item}
  1236. {    selection, otherwise pass the character and the modifiers flags}
  1237. {    to the active window's key handler.}
  1238.  
  1239. {    If dialogs are supported, there's no check for command-key}
  1240. {    equivalents, since that would have been checked in DoDialog.}
  1241.  
  1242.                 keydown, autokey:  begin
  1243.                     evtChar := char(BitAnd(theEvent.message, charCodeMask));
  1244.                     evtMods := theEvent.modifiers;
  1245.                     if BitAnd(evtMods, cmdKey) > 0 then
  1246.                         DoMenuCommand(menuKey(evtChar))
  1247.                     else
  1248.                         DoKey(GetWHandler(FrontWindow), evtChar, evtMods);
  1249.                 end;
  1250.  
  1251. {    Update a window.}
  1252.  
  1253.                 updateEvt: 
  1254.                     DoUpdate(GetWHandler(WindowPtr(theEvent.message)));
  1255.  
  1256. {    Activate or deactivate a window.}
  1257.  
  1258.                 activateEvt: 
  1259.                     DoActivate(GetWHandler(WindowPtr(theEvent.message)), (BitAnd(theEvent.modifiers, activeFlag) <> 0));
  1260.  
  1261. {    handle inserts of uninitialized disks}
  1262.  
  1263.                 diskEvt: 
  1264.                     if (HiWord(theEvent.message) <> noErr) then begin
  1265.                         DILoad;
  1266.                         ignore := DIBadMount(diskInitPt, theEvent.message);
  1267.                         DIUnload;
  1268.                     end;
  1269.  
  1270. { Handle suspend/resume and mouse moved events, added by Ingemar 23/7 -94}
  1271.  
  1272.                 osEvt: 
  1273.                     if BAND(BROTL(theEvent.message, 8), $FF) = suspendResumeMessage then begin
  1274. {Call the suspend/resume procedure, if any}
  1275.                         if gSuspendResumeHandler <> nil then
  1276.                             CallPBoolean(BAnd(theEvent.message, 1) <> 0, gSuspendResumeHandler);
  1277. {Added by Ingemar jan -95:}
  1278. {If we are MultiFinder aware, according to our SIZE -1, do activate or deactivate for the front window.}
  1279.                         if gMultiFinderAware then
  1280.                             DoActivate(GetWHandler(FrontWindow), BAnd(theEvent.message, 1) <> 0);
  1281.                     end
  1282.                     else if BAND(BROTL(theEvent.message, 8), $FF) = mouseMovedMessage then
  1283. {Added by Ingemar jan -95:}
  1284. {Mouse-moved event}
  1285.                         if gMouseMovedHandler <> nil then
  1286.                             CallPNoArg(gMouseMovedHandler);
  1287.  
  1288. { Handle Apple Events, added by Ingemar 23/7 -94}
  1289.  
  1290.                 kHighLevelEvent: 
  1291.                     ignore := AEProcessAppleEvent(theEvent);
  1292.  
  1293.                 otherwise
  1294.                     ;
  1295.             end;
  1296.         end;
  1297.     end;
  1298.  
  1299.     function DecodeEvent (ae: AppleEvent;
  1300.                                     actionProc: ProcPtr): OSErr;
  1301.         var
  1302.             err: OSErr;
  1303.             myFSS: FSSpec;
  1304.             docList: AEDescList;
  1305.             index, itemsInList: LongInt;
  1306.             actualSize: Size;
  1307.             keywd: AEKeyword;
  1308.             returnedType: DescType;
  1309.     begin
  1310.         { Decode the event we just received }
  1311.         err := AEGetParamDesc(ae, keyDirectObject, typeAEList, docList);
  1312.         err := AECountItems(docList, itemsInList);
  1313.         if itemsInList > 0 then
  1314.             for index := 1 to itemsInList do begin
  1315.                 if err = noErr then
  1316.                     err := AEGetNthPtr(docList, index, typeFSS, keywd, returnedType, @myFSS, SizeOf(myFSS), actualSize);
  1317.                 if err = noErr then begin { do something with the file }
  1318.                     err := CallFLongInt(LongInt(@myFSS), actionProc); { Pretend it's a longint for type-casting's sake }
  1319.                 end; { if noErr }
  1320.             end; { for index }
  1321.         DecodeEvent := err;
  1322.     end; { DecodeEvent }
  1323.  
  1324.     function SkelHandleOAPP (var theAppleEvent: AppleEvent;
  1325.                                     var reply: AppleEvent;
  1326.                                     handlerRefCon: LongInt): OSErr;
  1327.     begin
  1328.         {$UNUSED theAppleEvent, reply, handlerRefCon}
  1329. { Do some stuff when the application starts up.             }
  1330. { If there is a procedure to call, do it }
  1331.         if oappProc <> nil then
  1332.             CallPNoArg(oappProc);
  1333.         SkelHandleOAPP := noErr;
  1334.     end; { SkelHandleOAPP }
  1335.  
  1336.     function SkelHandleODOC (var theAppleEvent: AppleEvent;
  1337.                                     var reply: AppleEvent;
  1338.                                     handlerRefCon: LongInt): OSErr;
  1339.         var
  1340.             err: OSErr;
  1341.     begin
  1342.         {$UNUSED reply, handlerRefCon}
  1343.         err := errAEEventNotHandled;
  1344.         if odocProc <> nil then  { User has given us a procedure to work with }
  1345.             err := DecodeEvent(theAppleEvent, odocProc);
  1346.         SkelHandleODOC := err;
  1347.     end; { HandleODOC }
  1348.  
  1349.     function SkelHandlePDOC (var theAppleEvent: AppleEvent;
  1350.                                     var reply: AppleEvent;
  1351.                                     handlerRefCon: LongInt): OSErr;
  1352.         var
  1353.             err: OSErr;
  1354.     begin
  1355.         {$UNUSED reply, handlerRefCon}
  1356.         err := errAEEventNotHandled;
  1357.         if pdocProc <> nil then  { User has given us a procedure to work with }
  1358.             err := DecodeEvent(theAppleEvent, pdocProc);
  1359.         SkelHandlePDOC := err;
  1360.     end; { SkelHandlePDOC }
  1361.  
  1362.     function SkelHandleQUIT (var theAppleEvent: AppleEvent;
  1363.                                     var reply: AppleEvent;
  1364.                                     handlerRefCon: LongInt): OSErr;
  1365.     begin
  1366.         {$UNUSED theAppleEvent, reply, handlerRefCon}
  1367.         SkelHandleQUIT := noErr;
  1368. { If there is a procedure to call, do it }
  1369.         if quitProc <> nil then begin
  1370.             if not CallFNoArg(quitProc) then
  1371.                 SkelHandleQUIT := userCanceledErr;
  1372.         end { if }
  1373.         else
  1374.             SkelWhoa;
  1375.     end; { SkelHandleQUIT }
  1376.  
  1377.  
  1378.  
  1379. { -------------------------------------------------------------------- }
  1380. {                        Interface (public) Routines                        }
  1381. { -------------------------------------------------------------------- }
  1382.  
  1383.  
  1384. {    Initialize the various Macintosh Managers.}
  1385. {    Set default upper limits on window sizing.}
  1386. {    FlushEvents does NOT toss disk insert events, so that disks}
  1387. {    inserted while the application is starting up don't result}
  1388. {    in dead drives.}
  1389. {    NoMasters is the number of times to call MoreMasters.  gzProc is the address of a user - provided}
  1390. {    grow zone function procedure to call if memory gets tight.  Pass nil if none to be used.    }
  1391.  
  1392.     procedure SkelInit;
  1393.         var
  1394.             i: integer;
  1395.  
  1396.         function CheckIfMultiFinderAware: Boolean;
  1397.             type
  1398. {The "SIZE" resource format:}
  1399.                 SizeResRecord = record
  1400.                         multiFinderFlags: Integer;
  1401.                         preferredSize, minimumSize: Longint;
  1402.                     end;
  1403.                 SizeResPtr = ^SizeResRecord;
  1404.                 SizeResHandle = ^SizeResPtr;
  1405.             var
  1406.                 mySize: SizeResHandle;
  1407.                 wasLoaded: Boolean;
  1408.         begin
  1409.             SetResLoad(false);
  1410.             mySize := SizeResHandle(Get1Resource('SIZE', -1));
  1411.             SetResLoad(true);
  1412.             if mySize = nil then
  1413.                 CheckIfMultiFinderAware := false
  1414.             else begin
  1415.                 wasLoaded := mySize^ <> nil;
  1416.                 if not wasLoaded then
  1417.                     LoadResource(Handle(mySize));
  1418.  
  1419.                 CheckIfMultiFinderAware := BitAnd(mySize^^.multiFinderFlags, $800) <> 0;
  1420.  
  1421.                 if not wasLoaded then
  1422.                     ReleaseResource(Handle(mySize));
  1423.             end;
  1424.         end;
  1425.  
  1426.     begin {SkelInit}
  1427.  
  1428. { For non-Lightspeed Pascal users, the following inits are included as a compile time option, }
  1429. {  See the $SETC definition at the beginning of the unit.  }
  1430.  
  1431. {$IFC UNDEFINED THINK_PASCAL }
  1432.         InitGraf(@qd.thePort);
  1433.         InitFonts;
  1434.         InitWindows;
  1435.         InitMenus;
  1436.         TEInit;
  1437.         InitDialogs(nil);
  1438.         MaxApplZone;
  1439. {$ENDC}
  1440.  
  1441.         FlushEvents(everyEvent - diskMask, 0);
  1442.         for i := 1 to noMasters do
  1443.             MoreMasters;
  1444.         if myGrowZone <> nil then
  1445.             SetGrowZone(myGrowZone);
  1446.  
  1447.         InitCursor;
  1448.  
  1449. {Added by Ingemar 12/11-93, for WNE-support:}
  1450.         WNEImplemented := NGetTrapAddress($60, ToolTrap) <> NgetTrapAddress($9F, ToolTrap);
  1451.         SkelSetSleep(defaultSleep);
  1452.         SkelSetMouseRgn(nil);
  1453. {End WNE-support}
  1454.  
  1455.         gMultiFinderAware := CheckIfMultiFinderAware;
  1456.  
  1457.         whList := nil;
  1458.         whClobOnRmve := true;
  1459.         SetRect(growRect, 80, 80, 512, 342 - LMGetMBarHeight);
  1460.         mhList := nil;
  1461.         mhClobOnRmve := true;
  1462.         appleID := 0;
  1463.         appleAboutProc := nil;
  1464.         doAbout := false;
  1465.         doneflag := 0;
  1466.         pBkgnd := nil;
  1467.         pEvent := nil;
  1468.         pEventflag := false;
  1469.         eventmask := everyEvent;
  1470.         diskInitPt.v := 120;
  1471.         diskInitPt.h := 100;
  1472. {$IFC supportDialogs }
  1473.         dlogEventMask := $16f;
  1474. {$ENDC}
  1475.  
  1476. {    Set upper limits of window sizing to machine screen size.  Allow}
  1477. {    for the menu bar.}
  1478.  
  1479.         GetWMgrPort(screenport);
  1480.         growRect.right := screenPort^.portRect.right;
  1481.         growRect.bottom := screenPort^.portRect.bottom - LMGetMBarHeight;
  1482.  
  1483. {    Set caching global variables to nil }
  1484.  
  1485.         oldWindow := nil;
  1486.         oldWDHandler := nil;
  1487.     end; {SkelInit}
  1488.  
  1489.  { Added by PhC 20/02/98 }
  1490.     procedure SkelReqdAEInit (myOAPP, myODOC, myPDOC, myQuit: ProcPtr);
  1491.         var
  1492.             err: OSErr;
  1493.             myHandlerUPP: AEEventHandlerUPP;
  1494.     begin
  1495. { Set these global variables, will be used later in the appropriate AE handling procedures }
  1496.         oappProc := myOAPP;
  1497.         odocProc := myODOC;
  1498.         pdocProc := myPDOC;
  1499.         quitProc := myQUIT;
  1500.  
  1501. { Install the 4 core Apple Events }
  1502.         myHandlerUPP := NewAEEventHandlerProc(@SkelHandleOAPP);
  1503.         err := AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, myHandlerUPP, 0, False);
  1504.  
  1505.         myHandlerUPP := NewAEEventHandlerProc(@SkelHandleODOC);
  1506.         err := AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, myHandlerUPP, 0, False);
  1507.  
  1508.         myHandlerUPP := NewAEEventHandlerProc(@SkelHandlePDOC);
  1509.         err := AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, myHandlerUPP, 0, False);
  1510.  
  1511.         myHandlerUPP := NewAEEventHandlerProc(@SkelHandleQuit);
  1512.         err := AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, myHandlerUPP, 0, False);
  1513.  
  1514. { For some reason, if I dispose of the UPP the last element of the dispatch table won't make it... }
  1515. {        DisposePtr(Ptr(myHandlerUPP));}
  1516.     end; { SkelReqdAEInit }
  1517.  
  1518.  
  1519. {    Main loop.}
  1520.  
  1521. {    Task care of DA's with SystemTask.}
  1522. {    Run background task if there is one.}
  1523. {    If there is an event, check for an event hook.  If there isn't}
  1524. {    one defined, or if there is but it returns false, call the}
  1525. {    general event handler.  (Hook returns true if TransSkel should}
  1526. {    ignore the event.)}
  1527. {    If no event, call the "no-event" handler for the front window and for}
  1528. {    any other windows with idle procedures that are always supposed}
  1529. {    to run.  This is done in such a way that it is safe for idle procs}
  1530. {    to remove the handler for their own window if they want (unlikely,}
  1531. {    but...)  This loop doesn't check whether the window is really}
  1532. {    a dialog window or not, but it doesn't have to, because such}
  1533. {    things always have a nil idle proc.}
  1534. {    }
  1535. {    doneFlag is reset upon exit.  This allows it to be called}
  1536. {    repeatedly, or recursively.}
  1537.  
  1538. {    Null events are looked at (in SkelMain)}
  1539. {    and passed to the event handler.  This is necessary to make sure}
  1540. {    DialogSelect gets called repeatedly, or the caret won't blink if}
  1541. {    a dialog has any editText items.  Null events are not passed to any event-inspecting hook that may}
  1542. {    be installed.}
  1543.  
  1544.     procedure SkelMain;
  1545.  
  1546.         var
  1547.             theEvent: EventRecord;
  1548.             wh, wh2: WHandlerHnd;
  1549.             w: WindowPtr;
  1550.             haveEvent, testpevent: Boolean;
  1551.             tmpPort: GrafPtr;
  1552.             p: ProcPtr;
  1553.  
  1554.     begin
  1555.         while doneFlag = 0 do begin
  1556.             if WNEImplemented then {Added by Ingemar 12/11-93, for WNE-support:}
  1557.                 begin
  1558.                 if pBkgnd <> nil then
  1559.                     CallPnoarg(pBkgnd);
  1560.                 haveEvent := WaitNextEvent(eventMask, theEvent, sleepTicks, mouseRgn);
  1561.             end
  1562.             else begin {Old way:}
  1563.                 SystemTask;
  1564.                 if pBkgnd <> nil then
  1565.                     CallPnoarg(pBkgnd);
  1566.                 haveEvent := GetNextEvent(eventMask, theEvent);
  1567.             end;
  1568.  
  1569.             if pEvent <> nil then
  1570.                 testpevent := CallotherEvent(theEvent, pEvent)
  1571.             else
  1572.                 testpevent := false;
  1573. { following line fixed from version 1.02 & 1.03     [but was still buggy! /Ingemar]}
  1574. {$IFC supportDialogs }
  1575.             if not testpevent then {haveEvent and <- This is wrong for modeless dialogs according to page 416? Changed by Ingemar 6/8 -93}
  1576. {$ELSEC}
  1577.                 if haveEvent and ((pEvent = nil) or (testpevent = false)) then { Old line. IFC'ad by Ingemar 6/8 -93}
  1578. {$ENDC}
  1579.                     DoEvent(theEvent);
  1580.             if not haveEvent then begin
  1581.                 wh := whList;
  1582.                 GetPort(tmpPort);
  1583.                 while wh <> nil do begin
  1584.                     wh2 := wh^^.whNext;
  1585.                     w := wh^^.whWind;
  1586.                     if ((w = FrontWindow) or not wh^^.whFrontOnly) then begin
  1587.                         SystemTask;
  1588.                         if (wh^^.whIdle <> nil) then begin
  1589.                             SetPort(wh^^.whWind);
  1590.                             p := wh^^.whIdle;
  1591.                             if (p <> nil) then
  1592.                                 CallPnoarg(p);
  1593.                         end;
  1594.                     end;
  1595.                     wh := wh2;
  1596.                 end;
  1597.                 SetPort(tmpPort);
  1598.             end;
  1599.         end;
  1600.         doneFlag := 0;
  1601.     end;
  1602.  
  1603. {    Tell SkelMain to stop}
  1604.  
  1605.     procedure SkelWhoa;
  1606.     begin
  1607.         doneFlag := 1;
  1608.     end;
  1609.  
  1610. {    Clobber all the menu, window and dialog handlers}
  1611.  
  1612.     procedure SkelClobber;
  1613.  
  1614.  
  1615.     begin
  1616.         oldWDHandler := nil;
  1617.         oldWindow := nil;
  1618.         while (whList <> nil) do begin
  1619.             SkelRmveWind(whList^^.whWind);
  1620.         end;
  1621.         while (mhList <> nil) do begin
  1622.             SkelRmveMenu(GetMenuHandle(mhList^^.mhID));
  1623.         end;
  1624.     end;
  1625.  
  1626. { -------------------------------------------------------------------- }
  1627. {                        Menu-handler interface routines                            }
  1628. { -------------------------------------------------------------------- }
  1629.  
  1630.  
  1631.  
  1632.  
  1633. {    Install handler for a menu.  Remove any previous handler for it.}
  1634. {    Pass the following parameters:}
  1635.  
  1636. {    theMenu    Handle to the menu to be handled.  Must be created by host.}
  1637. {    pSelect    Proc that handles selection of items from menu.  If this is}
  1638. {            nil, the menu is installed, but nothing happens when items}
  1639. {            are selected from it.}
  1640. {    pClobber Proc for disposal of handler's data structures.  Usually}
  1641. {            nil for menus that remain in menu bar until program}
  1642. {            termination.}
  1643.  
  1644. {    The menu is installed and drawn in the menu bar.}
  1645.  
  1646. {     Return false if no handler could be allocated, true if successful. }
  1647.  
  1648.     function CommonSkelMenu (theMenu: MenuHandle;
  1649.                                     pSelect: ProcPtr;
  1650.                                     pClobber: ProcPtr): Boolean;
  1651.         var
  1652.             mh: MHandlerHnd;
  1653.             myHand: Handle;
  1654.     begin
  1655.         mhClobOnRmve := false;
  1656.         SkelRmveMenu(theMenu);
  1657.         mhClobOnRmve := true;
  1658.         myHand := NewHandle(Sizeof(MHandler));
  1659.         CommonSkelMenu := false;
  1660.         if myHand <> nil then begin
  1661.             CommonSkelMenu := true;                    { show we really got the memory }
  1662.             mh := MHandlerHnd(myHand);
  1663.             mh^^.mhNext := mhList;
  1664.             mhList := MHandlerHnd(myHand);
  1665.             mh^^.mhID := theMenu^^.menuID;    { get menu id number }
  1666.             mh^^.mhSelect := pSelect;            { install selection handler }
  1667.             mh^^.mhClobber := pClobber;        { install disposal handler }
  1668.         end;
  1669.     end;
  1670.  
  1671. {  Install handler for a normal menu }
  1672.  
  1673.     function SkelMenu;
  1674.         var
  1675.             success: Boolean;
  1676.     begin
  1677.         success := CommonSkelMenu(theMenu, pSelect, pClobber);
  1678.         SkelMenu := success;
  1679.         if success then begin
  1680.             InsertMenu(theMenu, 0);            { put menu at end of menu bar }
  1681.             if DrawBar then
  1682.                 DrawMenuBar;
  1683.         end;
  1684.     end;
  1685.  
  1686. {    Install handler for a hiearcical menu.  Almost same as above.}
  1687. {    Added by Ingemar 22/8 -93}
  1688.  
  1689.     function SkelHMenu;
  1690.         var
  1691.             success: Boolean;
  1692.     begin
  1693.         success := CommonSkelMenu(theMenu, pSelect, pClobber);
  1694.         SkelHMenu := success;
  1695.         if success then begin
  1696.             InsertMenu(theMenu, -1);            { put menu at end of menu bar }
  1697.         end;
  1698.     end;
  1699.  
  1700.  
  1701. {    Remove a menu handler.  This calls the handler's disposal routine}
  1702. {    and then takes the handler out of the handler list and disposes}
  1703. {    of it.}
  1704.  
  1705. {    Note that the menu MUST be deleted from the menu bar before calling}
  1706. {    the clobber proc, because the menu bar will end up filled with}
  1707. {    garbage if the menu was allocated with NewMenu (see discussion of}
  1708. {    DisposeMenu in Menu Manager section of Inside Macintosh).}
  1709.  
  1710.     procedure SkelRmveMenu;
  1711.  
  1712.         var
  1713.             mID: integer;
  1714.             h, h2: MHandlerHnd;
  1715.             p: ProcPtr;
  1716.             returnflag: Boolean;
  1717.  
  1718.     begin
  1719.         mID := theMenu^^.menuID;
  1720.         returnflag := false;
  1721.         if mhlist <> nil then begin
  1722.             if mhList^^.mhID = mID then begin
  1723.                 h2 := mhlist;
  1724.                 mhList := h2^^.mhNext;
  1725.             end
  1726.             else begin
  1727.                 h := mhList;
  1728.                 while (h <> nil) and not returnflag do begin
  1729.                     h2 := h^^.mhNext;
  1730.                     if (h2 = nil) then begin
  1731.                         h := nil;
  1732.                         returnflag := true;
  1733.                     end
  1734.                     else if h2^^.mhID = mID then begin
  1735.                         h^^.mhNext := h2^^.mhNext;
  1736.                         h := nil;
  1737.                     end;
  1738.                     if h <> nil then
  1739.                         h := h2;
  1740.                 end;
  1741.             end;
  1742.             if not returnflag then begin
  1743.                 DeleteMenu(mID);
  1744.                 DrawMenuBar;
  1745.                 p := h2^^.mhClobber;
  1746.                 if mhClobOnRmve and (p <> nil) then
  1747.                     CallPMenu(theMenu, p);
  1748.                 DisposeHandle(Handle(h2));
  1749.             end;
  1750.         end;
  1751.     end;
  1752.  
  1753. {    Install a handler for the Apple menu.}
  1754.  
  1755. {    SkelApple is called if TransSkel is supposed to handle the apple}
  1756. {    menu itself.  The title is the title of the first item.  If nil,}
  1757. {    then only desk accessories are put into the menu.  If not nil, then}
  1758. {    the title is entered as the first item, followed by a gray line,}
  1759. {    then the desk accessories.}
  1760.  
  1761. {     SkelApple does not cause the menubar to be drawn, so if the Apple menu is the only menu, }
  1762. {    DrawMenuBar must be called afterward.}
  1763.  
  1764. {    No value is returned, unlike SkelMenu.  It is assumed that SkelApple will be called so early in the}
  1765. {    application that the call to SkelMenu is virtually certain to succeed.  }
  1766.  
  1767.     procedure SkelApple;
  1768.  
  1769.         var
  1770.             appleTitle: Str255;
  1771.             dummy: Boolean;
  1772.     begin
  1773.         appleTitle := ' ';
  1774.         appleTitle[1] := char($14);
  1775.         appleID := 1;
  1776.         appleMenu := NewMenu(appleID, appleTitle);
  1777.         if aboutTitle <> '' then begin
  1778.             doAbout := true;
  1779.             AppendMenu(appleMenu, aboutTitle);
  1780.             AppendMenu(appleMenu, '(-');
  1781.             AppleAboutProc := aboutProc;
  1782.         end;
  1783.         AppendResMenu(appleMenu, 'DRVR');
  1784.         dummy := SkelMenu(appleMenu, @DoAppleItem, @DoAppleClobber, false);
  1785.     end;
  1786.  
  1787. { In case the user wants to modify the Apple Menu, here is an accessor function to this }
  1788. { private variable }
  1789.     function SkelGetAppleMenu;
  1790.     begin
  1791.         SkelGetAppleMenu := appleMenu;
  1792.     end;
  1793. { -------------------------------------------------------------------- }
  1794. {                    Window-handler interface routines                    }
  1795. { -------------------------------------------------------------------- }
  1796.  
  1797.  
  1798.  
  1799. {    Install handler for a window.  Remove any previous handler for it.}
  1800. {    Pass the following parameters:}
  1801.  
  1802. {    theWind    Pointer to the window to be handled.  Must be created by host.}
  1803. {    pMouse    Proc to handle mouse clicks in window.  The proc will be}
  1804. {            passed the point (in local coordinates), the time of the}
  1805. {            click, and the modifier flags word.}
  1806. {    pKey    Proc to handle key clicks in window.  The proc will be passed}
  1807. {            the character and the modifier flags word.}
  1808. {    pUpdate    Proc for updating window.  TransSkel brackets calls to update}
  1809. {            procs with calls to BeginUpdate and EndUpdate, so the visRgn}
  1810. {            is set up correctly.  A flag is passed indicating whether the}
  1811. {            window was resized or not.  BY CONVENTION, the entire portRect}
  1812. {            is invalidated when the window is resized.  That way, the}
  1813. {            handler's update proc can redraw the entire content region}
  1814. {            without interference from BeginUpdate/EndUpdate.  The flag}
  1815. {            is set to false after the update proc is called; the}
  1816. {            assumption is made that it will notice the resizing and}
  1817. {            respond appropriately.}
  1818. {    pActivate Proc to execute when window is activated or deactivated.}
  1819. {            A boolean is passed to it which is true if the window is}
  1820. {            coming active, false if it's going inactive.}
  1821. {    pClose    Proc to execute when mouse clicked in close box.  Useful}
  1822. {            mainly to temp window handlers that want to know when to}
  1823. {            self-destruct (with SkelRmveWind).}
  1824. {    pClobber Proc for disposal of handler's data structures}
  1825. {    pIdle    Proc to execute when no events are pending.}
  1826. {    frontOnly True if pIdle should execute on no events only when}
  1827. {            theWind is frontmost, false if executes all the time.  Note}
  1828. {            that if it always goes, everything else may be slowed down!}
  1829.  
  1830. {    If a particular procedure is not needed (e.g., key events are}
  1831. {    not processed by a handler), pass nil in place of the appropriate}
  1832. {    procedure address.}
  1833.  
  1834. {    Return false  if no handler could be allocated, true if successful.}
  1835.  
  1836.     function SkelWindow;
  1837.  
  1838.         var
  1839.             hHand: WhandlerHnd;
  1840.  
  1841.     begin
  1842.         whClobOnRmve := false;
  1843.         SkelRmveWind(theWind);
  1844.         whClobOnRmve := true;
  1845.  
  1846. {    Get new handler, attach to list of handlers.  It is attached to the beginning of the list, which is simpler;}
  1847. {    the order should be irrelevant to the hose, anyway. }
  1848.  
  1849.         hHand := WHandlerHnd(NewHandle(Sizeof(WHandler)));
  1850.         SkelWindow := false;
  1851.         if hHand <> nil then begin
  1852.             hHand^^.whNext := whList;
  1853.             whList := hHand;
  1854.             with hHand^^ do begin
  1855.                 SkelWindow := true;                    { Show that we got the memory }
  1856.                 whWind := theWind;
  1857.                 whMouse := pMouse;
  1858.                 whKey := pKey;
  1859.                 whUpdate := pUpdate;
  1860.                 whActivate := pActivate;
  1861.                 whClose := pClose;
  1862.                 whClobber := pClobber;
  1863.                 whIdle := pIdle;
  1864.                 whFrontOnly := frontOnly;
  1865.                 whSized := false;
  1866.                 whGrow := GrowRect;
  1867.             end;
  1868.         end;
  1869.         SetPort(theWind); {Is this allowed for hidden windows? I thought so, but… /Ingemar, dec 93}
  1870.     end;
  1871.  
  1872. {    Remove a window handler.  This calls the handler's disposal routine}
  1873. {    and then takes the handler out of the handler list and disposes}
  1874. {    of it.}
  1875.  
  1876. {    SkelRmveWind is also called by SkelRmveDlog.}
  1877.  
  1878. {    Note that if the window cache variable is set to the window whose handler is being clobbered, the }
  1879. {    variable must be zeroed.    }
  1880.  
  1881.     procedure SkelRmveWind;
  1882.  
  1883.         var
  1884.             h, h2: WHandlerHnd;
  1885.             returnflag: Boolean;
  1886.  
  1887.     begin
  1888.         if theWind = oldWindow then begin
  1889.             oldWindow := nil;
  1890. {•    oldWDHandler := nil;•}
  1891.         end;
  1892.  
  1893.         if (whList <> nil) then begin
  1894.             returnflag := false;
  1895.             if whList^^.whWind = theWind then begin
  1896.                 h2 := whlist;
  1897.                 whList := whList^^.whNext;
  1898.             end
  1899.             else begin
  1900.                 h := whList;
  1901.                 while (h <> nil) and not returnflag do begin
  1902.                     h2 := h^^.whNext;
  1903.                     if (h2 = nil) then begin
  1904.                         h := nil;
  1905.                         returnflag := true;
  1906.                     end
  1907.                     else if h2^^.whWind = theWind then begin
  1908.                         h^^.whNext := h2^^.whNext;
  1909.                         h := nil;
  1910.                     end;
  1911.                     if h <> nil then
  1912.                         h := h2;
  1913.                 end;
  1914.             end;
  1915.             if not returnflag then begin
  1916.                 if (whClobOnRmve) then
  1917.                     DoClobber(h2);
  1918.                 DisposeHandle(Handle(h2));
  1919.             end;
  1920.         end;
  1921.     end;
  1922.  
  1923. {$IFC supportDialogs }
  1924.  
  1925. { -------------------------------------------------------------------- }
  1926. {                    Dialog-handler interface routines                                }
  1927. { -------------------------------------------------------------------- }
  1928.  
  1929.  
  1930.  
  1931. {    Install a dialog handler.  Remove any previous handler for it.}
  1932. {    SkelDialog calls SkelWindow as a subsidiary to install a window}
  1933. {    handler, then sets the event procedure on return.}
  1934.  
  1935. {    Pass the following parameters:}
  1936.  
  1937. {    theDialog    Pointer to the dialog to be handled.  Must be created}
  1938. {            by host.}
  1939. {    pEvent    Event-handling proc for dialog events.}
  1940. {    pClose    Proc to execute when mouse clicked in close box.  Useful}
  1941. {            mainly to dialog handlers that want to know when to}
  1942. {            self-destruct (with SkelRmveDlog).}
  1943. {    pClobber Proc for disposal of handler's data structures}
  1944.  
  1945. {    If a particular procedure is not needed, pass nil in place of}
  1946. {    the appropriate procedure address.}
  1947.  
  1948. {    Return false if no handler could be allocated, true if successful.}
  1949.  
  1950.     function SkelDialog;
  1951.  
  1952.         var
  1953.             wh: WHandlerHnd;
  1954.             aBool: Boolean;
  1955.  
  1956.     begin
  1957.         aBool := SkelWindow(theDialog, nil, nil, nil, nil, pClose, pClobber, nil, false);
  1958.         if aBool <> false then begin
  1959.             wh := GetWDHandler(theDialog);
  1960.             wh^^.whEvent := pEvent;
  1961. {Added by Ingemar 18/9 -93:}
  1962.             wh^^.whFilter := pFilter; {Install a filter function to be called *before* IsDialogEvent!}
  1963.         end;
  1964.         SkelDialog := aBool;
  1965.     end;
  1966.  
  1967. {    Remove a dialog and its handler}
  1968.  
  1969.     procedure SkelRmveDlog;
  1970.  
  1971.     begin
  1972.         SkelRmveWind(theDialog);
  1973.     end;
  1974. {$ENDC}
  1975. { -------------------------------------------------------------------- }
  1976. {                    Miscellaneous interface routines                    }
  1977. { -------------------------------------------------------------------- }
  1978.  
  1979.  
  1980. {    Override the default sizing limits for a window, or, if theWind}
  1981. {    is nil, reset the default limits used by SkelWindow.}
  1982.  
  1983.     procedure SkelGrowBounds;
  1984.  
  1985.         var
  1986.             h: WHandlerHnd;
  1987.             r: Rect;
  1988.  
  1989.     begin
  1990.         if theWind = nil then
  1991.             SetRect(growRect, hLo, vLo, hHi, vHi)
  1992.         else begin
  1993.             h := GetWHandler(theWind);
  1994.             if h <> nil then begin
  1995.                 SetRect(r, hLo, vLo, hHi, vHi);
  1996.                 h^^.whGrow := r;
  1997.             end;
  1998.         end;
  1999.     end;
  2000.  
  2001. {    Set the event mask.}
  2002.  
  2003.     procedure SkelEventMask;
  2004.  
  2005.     begin
  2006.         eventMask := mask;
  2007.     end;
  2008.  
  2009. {    Return the event mask.}
  2010.  
  2011.     procedure SkelGetEventMask;
  2012.  
  2013.     begin
  2014.         mask := eventMask;
  2015.     end;
  2016.  
  2017. {    Install a background task.  If p is nil, the current task is}
  2018. {    disabled.}
  2019.  
  2020.     procedure SkelBackground;
  2021.  
  2022.     begin
  2023.         pBkgnd := p;
  2024.     end;
  2025.  
  2026. {    Return the current background task.  Return nil if none.}
  2027.  
  2028.     procedure SkelGetBackground;
  2029.     begin
  2030.         p := pBkgnd;
  2031.     end;
  2032.  
  2033. {    Install an event-inspecting hook.  If p is nil, the hook is}
  2034. {    disabled.}
  2035.  
  2036.     procedure SkelEventHook;
  2037.  
  2038.     begin
  2039.         pEvent := p;
  2040.     end;
  2041.  
  2042.     procedure SkelGetEventHook;
  2043.  
  2044.     begin
  2045.         p := pEvent;
  2046.     end;
  2047. {$IFC supportDialogs }
  2048.  
  2049. {    Set the mask for event types that will be passed to dialogs.}
  2050. {    Bit 1 is always set, so that null events will be passed.}
  2051. {    If this is not done, the caret does not blink in editText items.}
  2052.  
  2053.     procedure SkelDlogMask;
  2054.  
  2055.     begin
  2056.         dlogEventMask := BitOr(mask, 1);
  2057.     end;
  2058.  
  2059. {    Return the current dialog event mask.}
  2060.  
  2061.     procedure SkelGetDlogMask;
  2062.  
  2063.     begin
  2064.         mask := dlogEventMask;
  2065.     end;
  2066. {$ENDC}
  2067. end.